package cn.iocoder.yudao.module.ao.service.classdiscipline;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;
import java.time.LocalDateTime;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.ss.util.CellRangeAddress;
import cn.iocoder.yudao.module.ao.controller.admin.classdiscipline.vo.*;
import cn.iocoder.yudao.module.ao.dal.dataobject.classdiscipline.ClassDisciplineDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import cn.iocoder.yudao.module.ao.dal.mysql.classdiscipline.ClassDisciplineMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
import static cn.iocoder.yudao.module.ao.enums.ErrorCodeConstants.*;

/**
 * 高技课堂纪律情况登记 Service 实现类
 *
 * @author 小y
 */
@Service
@Validated
public class ClassDisciplineServiceImpl implements ClassDisciplineService {

    @Resource
    private ClassDisciplineMapper classDisciplineMapper;

    @Override
    public Long createClassDiscipline(ClassDisciplineSaveReqVO createReqVO) {
        // 插入
        ClassDisciplineDO classDiscipline = BeanUtils.toBean(createReqVO, ClassDisciplineDO.class);
        classDisciplineMapper.insert(classDiscipline);

        // 返回
        return classDiscipline.getRecordId();
    }

    @Override
    public void updateClassDiscipline(ClassDisciplineSaveReqVO updateReqVO) {
        // 校验存在
        validateClassDisciplineExists(updateReqVO.getRecordId());
        // 更新
        ClassDisciplineDO updateObj = BeanUtils.toBean(updateReqVO, ClassDisciplineDO.class);
        classDisciplineMapper.updateById(updateObj);
    }

    @Override
    public void deleteClassDiscipline(Long id) {
        // 校验存在
        validateClassDisciplineExists(id);
        // 删除
        classDisciplineMapper.deleteById(id);
    }

    @Override
    public void deleteClassDisciplineListByIds(List<Long> ids) {
        // 校验参数
        if (ids == null || ids.isEmpty()) {
            return;
        }
        // 过滤掉null值
        ids = ids.stream()
                .filter(id -> id != null)
                .collect(Collectors.toList());
        if (ids.isEmpty()) {
            return;
        }
        // 删除
        classDisciplineMapper.deleteByIds(ids);
    }


    private void validateClassDisciplineExists(Long id) {
        if (classDisciplineMapper.selectById(id) == null) {
            throw exception(CLASS_DISCIPLINE_NOT_EXISTS);
        }
    }

    @Override
    public ClassDisciplineDO getClassDiscipline(Long id) {
        return classDisciplineMapper.selectById(id);
    }

    @Override
    public PageResult<ClassDisciplineDO> getClassDisciplinePage(ClassDisciplinePageReqVO pageReqVO) {
        return classDisciplineMapper.selectPage(pageReqVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ClassDisciplineImportRespVO importClassDisciplineList(List<ClassDisciplineImportReqVO> importList, Boolean updateSupport) {
        if (CollUtil.isEmpty(importList)) {
            throw exception(CLASS_DISCIPLINE_NOT_EXISTS);
        }
        
        System.out.println("========== 开始导入 ==========");
        System.out.println("总记录数: " + importList.size());
        System.out.println("是否支持更新: " + updateSupport);
        
        ClassDisciplineImportRespVO.ClassDisciplineImportRespVOBuilder respBuilder = ClassDisciplineImportRespVO.builder();
        List<Map<String, Object>> failureList = new ArrayList<>();
        int createSuccessCount = 0;
        int updateSuccessCount = 0;
        int failureCount = 0;

        for (int i = 0; i < importList.size(); i++) {
            ClassDisciplineImportReqVO importReqVO = importList.get(i);
            try {
                // 校验数据
                validateImportData(importReqVO);
                
                // 手动转换为DO对象（因为字段名不匹配）
                ClassDisciplineDO classDiscipline = ClassDisciplineDO.builder()
                    .recordId(importReqVO.getRecordId()) // 设置记录编号
                    .fillTime(importReqVO.getFillTime())
                    .className(importReqVO.getClassName())
                    .classSession(importReqVO.getClassSession())
                    .eveningSession(importReqVO.getEveningSession())
                    .unbaggedPhones(importReqVO.getUnbaggedPhones())
                    .absentCount(importReqVO.getAbsentCount())
                    .specialAbsentCount(importReqVO.getSpecialAbsentCount())
                    .isSalute(importReqVO.getIsSalute())
                    .isRollCall(importReqVO.getIsRollCall())
                    .isAssignShowHomework(importReqVO.getIsAssignShowHomework())
                    .eveningHomeworkContent(importReqVO.getEveningHomeworkContent())
                    .remark(importReqVO.getRemark())
                    .imageUrl(importReqVO.getImageUrl())
                    .processStatus(importReqVO.getProcessStatus())
                    .filler(importReqVO.getFiller())
                    .build();
                
                // 判断是新增还是更新（根据填表时间和班级）
                Long recordId = importReqVO.getRecordId();
                LocalDateTime fillTime = importReqVO.getFillTime();
                String className = importReqVO.getClassName();
                
                System.out.println("第" + (i+1) + "行: 班级=" + className + ", 填表时间=" + fillTime);
                
                // 根据填表时间（精确到时分秒）和班级查找已存在的记录
                ClassDisciplineDO existingRecord = null;
                if (fillTime != null && StrUtil.isNotBlank(className)) {
                    existingRecord = classDisciplineMapper.selectOne(
                        new LambdaQueryWrapperX<ClassDisciplineDO>()
                            .eq(ClassDisciplineDO::getClassName, className)
                            .eq(ClassDisciplineDO::getFillTime, fillTime)
                            .last("LIMIT 1")
                    );
                }
                
                if (existingRecord != null && updateSupport) {
                    // 记录存在且支持更新
                    System.out.println("  -> 更新记录 ID=" + existingRecord.getRecordId());
                    classDiscipline.setRecordId(existingRecord.getRecordId());
                    classDisciplineMapper.updateById(classDiscipline);
                    updateSuccessCount++;
                } else if (existingRecord != null && !updateSupport) {
                    // 记录存在但不支持更新，跳过
                    System.out.println("  -> 记录已存在，跳过");
                    Map<String, Object> failureData = createFailureData(importReqVO, i + 1, "数据已存在（班级：" + className + "，时间：" + fillTime + "），未选择更新");
                    failureList.add(failureData);
                    failureCount++;
                } else {
                    // 记录不存在，创建新记录
                    System.out.println("  -> 创建新记录");
                    classDiscipline.setRecordId(null);
                    classDisciplineMapper.insert(classDiscipline);
                    createSuccessCount++;
                }
            } catch (Exception e) {
                System.out.println("  -> 失败: " + e.getMessage());
                e.printStackTrace();
                Map<String, Object> failureData = createFailureData(importReqVO, i + 1, e.getMessage());
                failureList.add(failureData);
                failureCount++;
            }
        }

        System.out.println("========== 导入完成 ==========");
        System.out.println("创建成功: " + createSuccessCount);
        System.out.println("更新成功: " + updateSuccessCount);
        System.out.println("失败: " + failureCount);

        return respBuilder
                .createSuccessCount(createSuccessCount)
                .updateSuccessCount(updateSuccessCount)
                .failureCount(failureCount)
                .failureList(failureList)
                .build();
    }

    /**
     * 校验导入数据
     */
    private void validateImportData(ClassDisciplineImportReqVO importReqVO) {
        System.out.println("=== 导入数据调试 ===");
        System.out.println("班级名称: [" + importReqVO.getClassName() + "]");
        System.out.println("填表时间字符串: [" + importReqVO.getFillTimeStr() + "]");
        System.out.println("填表人: [" + importReqVO.getFiller() + "]");
        System.out.println("==================");
        
        if (StrUtil.isBlank(importReqVO.getClassName())) {
            throw new IllegalArgumentException("班级不能为空，实际值：[" + importReqVO.getClassName() + "]");
        }
        
        // 校验填表时间
        LocalDateTime fillTime = importReqVO.getFillTime();
        if (fillTime == null) {
            throw new IllegalArgumentException("填表时间不能为空或格式错误，实际值：[" + importReqVO.getFillTimeStr() + "]");
        }
        
        // 设置默认值
        if (StrUtil.isBlank(importReqVO.getFiller())) {
            importReqVO.setFiller("系统导入");
        }
        
        if (StrUtil.isBlank(importReqVO.getProcessStatus())) {
            importReqVO.setProcessStatus("未处理");
        }
        
        // 预先调用转换方法，确保数据格式正确
        importReqVO.getClassSession();
        importReqVO.getEveningSession();
        importReqVO.getUnbaggedPhones();
        importReqVO.getAbsentCount();
        importReqVO.getSpecialAbsentCount();
        importReqVO.getIsSalute();
        importReqVO.getIsRollCall();
        importReqVO.getIsAssignShowHomework();
    }

    /**
     * 创建失败数据
     */
    private Map<String, Object> createFailureData(ClassDisciplineImportReqVO importReqVO, int rowIndex, String errorMsg) {
        Map<String, Object> failureData = new HashMap<>();
        failureData.put("rowIndex", rowIndex);
        failureData.put("className", importReqVO.getClassName());
        failureData.put("filler", importReqVO.getFiller());
        failureData.put("errorMsg", errorMsg);
        return failureData;
    }

    @Override
    public void exportStatistics(ClassDisciplinePageReqVO pageReqVO, HttpServletResponse response) throws IOException {
        // 查询数据
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        List<ClassDisciplineDO> list = getClassDisciplinePage(pageReqVO).getList();
        
        if (list.isEmpty()) {
            throw new RuntimeException("没有可导出的数据");
        }
        
        // 从实际数据中提取日期
        List<LocalDate> allDates = extractDatesFromData(list);
        
        // 定义节次（去掉第八节，第五节改为学习力）
        String[] sessions = {"早读", "第一节", "第二节", "第三节", "第四节", 
                            "学习力", "第六节", "第七节", 
                            "晚自习第一节", "晚自习第二节"};
        
        // 获取所有班级
        List<String> classList = list.stream()
                .map(ClassDisciplineDO::getClassName)
                .distinct()
                .sorted()
                .collect(Collectors.toList());
        
        // 创建工作簿
        Workbook workbook = new XSSFWorkbook();
        
        // 创建统计表工作表（所有日期纵向排列在一个Sheet中）
        String firstDate = allDates.get(0).format(DateTimeFormatter.ofPattern("MM月dd日"));
        String lastDate = allDates.get(allDates.size() - 1).format(DateTimeFormatter.ofPattern("MM月dd日"));
        String sheetName = firstDate + "至" + lastDate;
        Sheet sheet = workbook.createSheet(sheetName);
        
        // 创建样式
        CellStyle headerStyle = createHeaderStyle(workbook);
        CellStyle dataStyle = createDataStyle(workbook);
        
        // 创建表格内容（纵向排列）
        createSheetContent(sheet, allDates, sessions, classList, list, headerStyle, dataStyle);
        
        // 输出到响应
        String filename = "课堂纪律统计表_" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + ".xlsx";
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + URLEncoder.encode(filename, "UTF-8"));
        
        workbook.write(response.getOutputStream());
        workbook.close();
    }
    
    /**
     * 创建工作表内容
     */
    private void createSheetContent(Sheet sheet, List<LocalDate> dateRange, String[] sessions, 
                                    List<String> classList, List<ClassDisciplineDO> list,
                                    CellStyle headerStyle, CellStyle dataStyle) {
        int rowNum = 0;
        
        // 为每个日期创建一个表格块
        for (LocalDate date : dateRange) {
            String dateStr = date.format(DateTimeFormatter.ofPattern("M月d日"));
            
            // 创建日期标题行（合并所有列）
            Row dateTitleRow = sheet.createRow(rowNum++);
            Cell dateCell = dateTitleRow.createCell(0);
            dateCell.setCellValue(dateStr);
            dateCell.setCellStyle(headerStyle);
            
            // 计算总列数：班级 + (节次数 × 4字段) + 未提交数据表
            int totalCols = 1 + (sessions.length * 4) + 1;
            sheet.addMergedRegion(new CellRangeAddress(rowNum - 1, rowNum - 1, 0, totalCols - 1));
            
            // 创建表头第一行（节次行）
            Row sessionRow = sheet.createRow(rowNum++);
            Cell cell = sessionRow.createCell(0);
            cell.setCellValue("班级");
            cell.setCellStyle(headerStyle);
            
            int colNum = 1;
            for (String session : sessions) {
                cell = sessionRow.createCell(colNum);
                cell.setCellValue(session);
                cell.setCellStyle(headerStyle);
                // 合并该节次的4个字段列
                sheet.addMergedRegion(new CellRangeAddress(rowNum - 1, rowNum - 1, colNum, colNum + 3));
                colNum += 4;
            }
            
            int lastColIndex = colNum;
            cell = sessionRow.createCell(lastColIndex);
            cell.setCellValue("未提交数据表");
            cell.setCellStyle(headerStyle);
            
            // 创建表头第二行（字段行）
            Row fieldRow = sheet.createRow(rowNum++);
            cell = fieldRow.createCell(0);
            cell.setCellStyle(headerStyle);
            
            colNum = 1;
            String[] fields = {"未入袋", "未到", "行礼", "点名"};
            for (int s = 0; s < sessions.length; s++) {
                for (String field : fields) {
                    cell = fieldRow.createCell(colNum++);
                    cell.setCellValue(field);
                    cell.setCellStyle(headerStyle);
                }
            }
            
            cell = fieldRow.createCell(lastColIndex);
            cell.setCellStyle(headerStyle);
            
            // 合并班级列和未提交数据表列的两行
            sheet.addMergedRegion(new CellRangeAddress(rowNum - 2, rowNum - 1, 0, 0)); // 班级列
            sheet.addMergedRegion(new CellRangeAddress(rowNum - 2, rowNum - 1, lastColIndex, lastColIndex)); // 未提交数据表列
            
            // 填充该日期的数据
            for (String className : classList) {
                Row dataRow = sheet.createRow(rowNum++);
                
                // 班级名称
                cell = dataRow.createCell(0);
                cell.setCellValue(className);
                cell.setCellStyle(dataStyle);
                
                colNum = 1;
                int missingCount = 0;
                
                // 按节次填充数据
                for (String session : sessions) {
                    ClassDisciplineDO record = findRecord(list, className, date, session);
                    
                    if (record != null) {
                        // 未入袋手机
                        cell = dataRow.createCell(colNum++);
                        cell.setCellValue(record.getUnbaggedPhones() != null ? record.getUnbaggedPhones() : 0);
                        cell.setCellStyle(dataStyle);
                        
                        // 未到人数
                        cell = dataRow.createCell(colNum++);
                        cell.setCellValue(record.getAbsentCount() != null ? record.getAbsentCount() : 0);
                        cell.setCellStyle(dataStyle);
                        
                        // 行礼
                        cell = dataRow.createCell(colNum++);
                        cell.setCellValue(Boolean.TRUE.equals(record.getIsSalute()) ? "是" : "否");
                        cell.setCellStyle(dataStyle);
                        
                        // 点名
                        cell = dataRow.createCell(colNum++);
                        cell.setCellValue(Boolean.TRUE.equals(record.getIsRollCall()) ? "是" : "否");
                        cell.setCellStyle(dataStyle);
                    } else {
                        // 没有记录，显示"未填写"
                        for (int k = 0; k < 4; k++) {
                            cell = dataRow.createCell(colNum++);
                            cell.setCellValue("未填写");
                            cell.setCellStyle(dataStyle);
                        }
                        missingCount++;
                    }
                }
                
                // 未提交数据表统计
                cell = dataRow.createCell(lastColIndex);
                cell.setCellValue(missingCount);
                cell.setCellStyle(dataStyle);
            }
            
            // 在日期块之间添加一个空行
            if (date != dateRange.get(dateRange.size() - 1)) {
                rowNum++; // 跳过一行
            }
        }
        
        // 设置列宽
        sheet.setColumnWidth(0, 5000); // 班级列
        for (int i = 1; i < 1 + (sessions.length * 4); i++) {
            sheet.setColumnWidth(i, 3000);
        }
        sheet.setColumnWidth(1 + (sessions.length * 4), 3500); // 未提交数据表列
    }
    
    /**
     * 获取日期范围 - 只返回有数据的日期
     */
    private List<LocalDate> getDateRange(ClassDisciplinePageReqVO pageReqVO) {
        // 这里不再生成日期范围，改为从实际数据中提取
        return new ArrayList<>();
    }
    
    /**
     * 从数据中提取实际有数据的日期列表
     */
    private List<LocalDate> extractDatesFromData(List<ClassDisciplineDO> list) {
        return list.stream()
                .filter(record -> record.getFillTime() != null)
                .map(record -> record.getFillTime().toLocalDate())
                .distinct()
                .sorted()
                .collect(Collectors.toList());
    }
    
    /**
     * 查找记录
     */
    private ClassDisciplineDO findRecord(List<ClassDisciplineDO> list, String className, LocalDate date, String session) {
        return list.stream()
                .filter(record -> className.equals(record.getClassName()))
                .filter(record -> record.getFillTime() != null && 
                        record.getFillTime().toLocalDate().equals(date))
                .filter(record -> matchSession(record.getFillTime(), session))
                .findFirst()
                .orElse(null);
    }
    
    /**
     * 匹配节次
     */
    private boolean matchSession(LocalDateTime fillTime, String session) {
        int hour = fillTime.getHour();
        int minute = fillTime.getMinute();
        int timeInMinutes = hour * 60 + minute;
        
        switch (session) {
            case "早读": return timeInMinutes >= 480 && timeInMinutes <= 500; // 8:00-8:20
            case "第一节": return timeInMinutes >= 510 && timeInMinutes <= 555; // 8:30-9:15
            case "第二节": return timeInMinutes >= 565 && timeInMinutes <= 610; // 9:25-10:10
            case "第三节": return timeInMinutes >= 630 && timeInMinutes <= 675; // 10:30-11:15
            case "第四节": return timeInMinutes >= 685 && timeInMinutes <= 730; // 11:25-12:10
            case "学习力": return timeInMinutes >= 840 && timeInMinutes <= 885; // 14:00-14:45 (原第五节)
            case "第六节": return timeInMinutes >= 895 && timeInMinutes <= 940; // 14:55-15:40
            case "第七节": return timeInMinutes >= 960 && timeInMinutes <= 1005; // 16:00-16:45
            // 移除第八节
            case "晚自习第一节": return timeInMinutes >= 1140 && timeInMinutes <= 1185; // 19:00-19:45
            case "晚自习第二节": return timeInMinutes >= 1195 && timeInMinutes <= 1240; // 19:55-20:40
            default: return false;
        }
    }
    
    /**
     * 创建表头样式
     */
    private CellStyle createHeaderStyle(Workbook workbook) {
        CellStyle style = workbook.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        style.setBorderTop(BorderStyle.THIN);
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        
        Font font = workbook.createFont();
        font.setBold(true);
        font.setFontHeightInPoints((short) 10);
        style.setFont(font);
        
        return style;
    }
    
    /**
     * 创建数据样式
     */
    private CellStyle createDataStyle(Workbook workbook) {
        CellStyle style = workbook.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setBorderTop(BorderStyle.THIN);
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        
        Font font = workbook.createFont();
        font.setFontHeightInPoints((short) 10);
        style.setFont(font);
        
        return style;
    }

}